/**
 * 
 */
package org.xlab.baseframework.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.UUID;

import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Service;
import org.xlab.baseframework.annotation.Loggable;
import org.xlab.baseframework.dao.api.ISystemWebServiceSessionDAO;
import org.xlab.baseframework.domain.ISystemUserDomain;
import org.xlab.baseframework.domain.SystemWebServiceSession;
import org.xlab.baseframework.domain.enumerate.EnumDeletedIndentifying;
import org.xlab.baseframework.domain.enumerate.EnumWebServiceClientType;
import org.xlab.baseframework.domain.view.SystemWebServiceSessionVO;
import org.xlab.baseframework.exception.InactiveWebServiceSessionFoundexception;
import org.xlab.baseframework.exception.ObjectNotFoundException;
import org.xlab.baseframework.exception.PermissionDeniedException;
import org.xlab.baseframework.exception.SystemParameterNotFoundException;
import org.xlab.baseframework.exception.SystemRuntimeException;
import org.xlab.baseframework.exception.SystemWebServiceSessionNotFoundException;
import org.xlab.baseframework.exception.TooManyObjectsFoundException;
import org.xlab.baseframework.service.api.ISystemParameterService;
import org.xlab.baseframework.service.api.ISystemWebServiceSessionService;
import org.xlab.baseframework.system.PlatformDeclare;

/**
 * @author makubex
 * 
 */
@Service
public class SystemWebServiceSessionServiceImpl implements
		ISystemWebServiceSessionService {

	/**
	 * @serialField
	 */
	private static final long serialVersionUID = -1881604082922282699L;
	private static final Logger log = Logger
			.getLogger(SystemWebServiceSessionServiceImpl.class);
	@Autowired(required = true)
	@Qualifier("bpf_systemWSServiceMessageSource")
	private MessageSource messageSource;
	@Autowired(required = true)
	@Qualifier("bpf_systemParameterService")
	private ISystemParameterService systemParameterService;
	@Autowired(required = true)
	@Qualifier("bpf_systemWSSessionDAO")
	private ISystemWebServiceSessionDAO systemWebServiceSessionDAO;

	/**
	 * @see org.xlab.baseframework.service.api.ISystemWebServiceSessionService#checkExpired(java.lang.String)
	 */
	public boolean checkExpired(String sessionId) {
		try {
			SystemWebServiceSession session = this.findBySessionId(sessionId);
			Long timeout = Long.parseLong(this.systemParameterService
					.findByCode(PlatformDeclare.PARAM_WEBSERVICE_TIMEOUT_CODE,
							true).getValue()) * 60 * 1000;
			if (session.getLastUpdatedTime().getTime() + timeout < new Date()
					.getTime())
				return true;
			else
				return false;
		} catch (SystemWebServiceSessionNotFoundException e) {
			log.warn("Session [" + sessionId + "] can not be found.");
			return true;
		} catch (InactiveWebServiceSessionFoundexception e) {
			return true;
		} catch (NumberFormatException e) {
			e.printStackTrace();
			throw new SystemRuntimeException(e);
		} catch (SystemParameterNotFoundException e) {
			e.printStackTrace();
			throw new SystemRuntimeException(e);
		} catch (SystemRuntimeException e) {
			throw e;
		}
	}

	/**
	 * @see org.xlab.baseframework.service.api.IBaseService#convertToVO(org.xlab.baseframework.domain.INormalDomain)
	 */
	public SystemWebServiceSessionVO convertToVO(SystemWebServiceSession entity) {
		return new SystemWebServiceSessionVO(entity);
	}

	/**
	 * @see org.xlab.baseframework.service.api.IBaseService#convertToVOList(java.util.Collection)
	 */
	public List<SystemWebServiceSessionVO> convertToVOList(
			Collection<SystemWebServiceSession> entityCollection) {
		List<SystemWebServiceSessionVO> result = new ArrayList<SystemWebServiceSessionVO>(
				entityCollection.size());
		for (SystemWebServiceSession entity : entityCollection) {
			result.add(this.convertToVO(entity));
		}
		return result;
	}

	private String createNewSession(ISystemUserDomain createdBy,
			String clientId, EnumWebServiceClientType clientType) {
		SystemWebServiceSession session = new SystemWebServiceSession();
		session.setClientId(clientId);
		session.setCreatedBy(createdBy.getUserCode());
		session.setClientType(clientType);
		Date current = new Date();
		session.setCreatedTime(current);
		session.setDeletedInd(EnumDeletedIndentifying.N);
		session.setLastUpdatedBy(createdBy.getUserCode());
		session.setLastUpdatedTime(current);
		String sessionId = UUID.randomUUID().toString();
		session.setSessionId(sessionId);
		this.systemWebServiceSessionDAO.save(session);
		return sessionId;
	}

	/**
	 * @see org.xlab.baseframework.service.api.ISystemWebServiceSessionService#
	 *      createSession(java.lang.String, java.lang.String,
	 *      org.xlab.baseframework.domain.enumerate.EnumWebServiceClientType)
	 */
	@Loggable
	public String createSession(ISystemUserDomain createdBy, String clientId,
			EnumWebServiceClientType clientType) {
		try {
			if ("TRUE"
					.equalsIgnoreCase(this.systemParameterService
							.findByCode(
									PlatformDeclare.PARAM_WEBSERVICE_SINGLESESSION_CODE,
									true).getValue().toLowerCase())) {
				SystemWebServiceSession live = this
						.findActiveSessionByClientId(clientId);
				log.debug("Return old session id.");
				return live.getSessionId();
			} else {
				log.debug("Creating new session...");
				return createNewSession(createdBy, clientId, clientType);
			}
		} catch (SystemParameterNotFoundException e) {
			log.warn("Can not find system parameter["
					+ PlatformDeclare.PARAM_WEBSERVICE_SINGLESESSION_CODE
					+ "].");
			throw new SystemRuntimeException(e);
		} catch (SystemRuntimeException e) {
			throw e;
		} catch (SystemWebServiceSessionNotFoundException e) {
			log.debug("No more alive session from client[" + clientId
					+ "]. Now creating new session...");
			return createNewSession(createdBy, clientId, clientType);
		}
	}

	/**
	 * @see org.xlab.baseframework.service.api.ISystemWebServiceSessionService#
	 *      deleteSession(java.lang.String)
	 */
	@Loggable
	public void deleteSession(String sessionId, ISystemUserDomain deletedBy)
			throws SystemWebServiceSessionNotFoundException {
		try {
			SystemWebServiceSession session = this.systemWebServiceSessionDAO
					.findByUniqueProperty("sessionId", sessionId);
			if (session.getDeletedInd() == EnumDeletedIndentifying.N) {
				session.setLastUpdatedBy(deletedBy.getUserCode());
				session.setLastUpdatedTime(new Date());
				this.systemWebServiceSessionDAO.logicRemove(session);
			}
		} catch (ObjectNotFoundException e) {
			throw new SystemWebServiceSessionNotFoundException(e);
		} catch (TooManyObjectsFoundException e) {
			e.printStackTrace();
			throw new SystemRuntimeException();
		}

	}

	/**
	 * @see org.xlab.baseframework.service.api.ISystemWebServiceSessionService#
	 *      findActiveSessionByClientId(java.lang.String)
	 */
	@Loggable
	public SystemWebServiceSession findActiveSessionByClientId(String clientId)
			throws SystemWebServiceSessionNotFoundException {
		SystemWebServiceSession exampleInstance = new SystemWebServiceSession();
		exampleInstance.setDeletedInd(EnumDeletedIndentifying.N);
		exampleInstance.setClientId(clientId);
		try {
			SystemWebServiceSession result = this.systemWebServiceSessionDAO
					.findAllByExample(exampleInstance).get(0);
			return result;
		} catch (ObjectNotFoundException e) {
			throw new SystemWebServiceSessionNotFoundException(e);
		}
	}

	/**
	 * @see org.xlab.baseframework.service.api.ISystemWebServiceSessionService#findAllActiveSession()
	 */
	public List<SystemWebServiceSession> findAllActiveSession()
			throws SystemWebServiceSessionNotFoundException {
		try {
			return this.systemWebServiceSessionDAO.findAllByProperty(
					"deletedInd", EnumDeletedIndentifying.N);
		} catch (ObjectNotFoundException e) {
			throw new SystemWebServiceSessionNotFoundException(e);
		}
	}

	/**
	 * @see org.xlab.baseframework.service.api.ISystemWebServiceSessionService#findBySessionId(java.lang.String)
	 */
	public SystemWebServiceSession findBySessionId(String sessionId)
			throws SystemWebServiceSessionNotFoundException,
			InactiveWebServiceSessionFoundexception {
		try {
			SystemWebServiceSession result = this.systemWebServiceSessionDAO
					.findByUniqueProperty("sessionId", sessionId);
			if (result.getDeletedInd() == EnumDeletedIndentifying.Y)
				throw new InactiveWebServiceSessionFoundexception(result);
			else
				return result;
		} catch (ObjectNotFoundException e) {
			String message = messageSource.getMessage(
					"err.service.session.findbysid",
					new Object[] { sessionId },
					"Could not find any session instance with session ID: ["
							+ sessionId + "].", Locale.getDefault());
			log.warn(message);
			throw new SystemWebServiceSessionNotFoundException(message, e);
		} catch (TooManyObjectsFoundException e) {
			e.printStackTrace();
			throw new SystemRuntimeException();
		}
	}

	/**
	 * @return the messageSource
	 */
	public MessageSource getMessageSource() {
		return messageSource;
	}

	/**
	 * @return the systemParameterService
	 */
	public ISystemParameterService getSystemParameterService() {
		return systemParameterService;
	}

	/**
	 * @return the systemWebServiceSessionDAO
	 */
	public ISystemWebServiceSessionDAO getSystemWebServiceSessionDAO() {
		return systemWebServiceSessionDAO;
	}

	/**
	 * @see org.xlab.baseframework.service.api.IBaseService#parseFromVO(org.xlab.baseframework.domain.view.IViewDomainObject)
	 */
	public SystemWebServiceSession parseFromVO(
			SystemWebServiceSessionVO viewObject) {
		SystemWebServiceSession pojo = new SystemWebServiceSession();
		BeanUtils.copyProperties(viewObject, pojo);
		return pojo;
	}

	/**
	 * @param messageSource
	 *            the messageSource to set
	 */
	public void setMessageSource(MessageSource messageSource) {
		this.messageSource = messageSource;
	}

	/**
	 * @param systemParameterService
	 *            the systemParameterService to set
	 */
	public void setSystemParameterService(
			ISystemParameterService systemParameterService) {
		this.systemParameterService = systemParameterService;
	}

	/**
	 * @param systemWebServiceSessionDAO
	 *            the systemWebServiceSessionDAO to set
	 */
	public void setSystemWebServiceSessionDAO(
			ISystemWebServiceSessionDAO systemWebServiceSessionDAO) {
		this.systemWebServiceSessionDAO = systemWebServiceSessionDAO;
	}

	/**
	 * @see org.xlab.baseframework.service.api.ISystemWebServiceSessionService#
	 *      updateStatus(java.lang.String, java.lang.String)
	 */
	@Loggable
	public void updateStatus(String sessionId, String clientId)
			throws SystemWebServiceSessionNotFoundException,
			PermissionDeniedException {
		SystemWebServiceSession exampleInstance = new SystemWebServiceSession();
		exampleInstance.setDeletedInd(EnumDeletedIndentifying.N);
		exampleInstance.setSessionId(sessionId);
		try {
			SystemWebServiceSession result = this.systemWebServiceSessionDAO
					.findAllByExample(exampleInstance).get(0);
			if (result.getClientId().equalsIgnoreCase(clientId)) {
				result.setLastUpdatedTime(new Date());
				result.setDeletedInd(EnumDeletedIndentifying.N);
				this.systemWebServiceSessionDAO.update(result);
			} else {
				throw new PermissionDeniedException();
			}
		} catch (ObjectNotFoundException e) {
			throw new SystemWebServiceSessionNotFoundException(e);
		}
	}

}
